#include "stdafx.h"

#include "dll_inject.h"
#include "functions.h"
#include "logger.h"
#include "storage_manager.h"
#include "var_init_once.h"

extern HINSTANCE g_hDllInst;

namespace {

#define PRE_X32SHELLCODE_ARGS_3_TO_1 \
    "\x58"         /* pop eax   */   \
    "\x59"         /* pop ecx   */   \
    "\x83\xC4\x08" /* add esp,8 */   \
    "\x51"         /* push ecx  */   \
    "\x50"         /* push eax  */

#define PRE_X32SHELLCODE_VIRTUAL_FREE                           \
    "\xFF\x74\x24\x04"         /* push dword ptr ss:[esp+4]  */ \
    "\xE8\x1E\x00\x00\x00"     /* call $+1E                  */ \
    "\x85\xC0"                 /* test eax,eax               */ \
    "\x75\x03"                 /* jne $+3                    */ \
    "\xC2\x04\x00"             /* ret 4                      */ \
    "\x59"                     /* pop ecx                    */ \
    "\x5A"                     /* pop edx                    */ \
    "\x68\x00\x80\x00\x00"     /* push 8000                  */ \
    "\x6A\x00"                 /* push 0                     */ \
    "\xE8\x00\x00\x00\x00"     /* call $                     */ \
    "\x66\x81\x24\x24\x00\xF0" /* and word ptr ss:[esp],F000 */ \
    "\x51"                     /* push ecx                   */ \
    "\xFF\xE0"                 /* jmp eax                    */

// The 32-bit InjectShellcode function from the project in the inject_shellcode
// subfolder.
const BYTE x32APCShellcode[] =
    PRE_X32SHELLCODE_ARGS_3_TO_1 PRE_X32SHELLCODE_VIRTUAL_FREE
    "\x55\x8B\xEC\x81\xEC\x6C\x01\x00\x00\x53\x56\x57\xC7\x85\x7C\xFF\xFF\xFF"
    "\x4B\x45\x52\x4E\x8D\x85\x6C\xFF\xFF\xFF\xC7\x45\x80\x45\x4C\x33\x32\xC7"
    "\x45\x84\x2E\x44\x4C\x4C\xC7\x85\x6C\xFF\xFF\xFF\x4C\x6F\x61\x64\xC7\x85"
    "\x70\xFF\xFF\xFF\x4C\x69\x62\x72\xC7\x85\x74\xFF\xFF\xFF\x61\x72\x79\x57"
    "\xC6\x85\x78\xFF\xFF\xFF\x00\xC7\x85\x4C\xFF\xFF\xFF\x47\x65\x74\x50\xC7"
    "\x85\x50\xFF\xFF\xFF\x72\x6F\x63\x41\xC7\x85\x54\xFF\xFF\xFF\x64\x64\x72"
    "\x65\x66\xC7\x85\x58\xFF\xFF\xFF\x73\x73\xC6\x85\x5A\xFF\xFF\xFF\x00\xC7"
    "\x45\xA0\x46\x72\x65\x65\xC7\x45\xA4\x4C\x69\x62\x72\xC7\x45\xA8\x61\x72"
    "\x79\x00\xC7\x45\x94\x56\x69\x72\x74\xC7\x45\x98\x75\x61\x6C\x46\xC7\x45"
    "\x9C\x72\x65\x65\x00\xC7\x85\x5C\xFF\xFF\xFF\x47\x65\x74\x4C\xC7\x85\x60"
    "\xFF\xFF\xFF\x61\x73\x74\x45\xC7\x85\x64\xFF\xFF\xFF\x72\x72\x6F\x72\xC6"
    "\x85\x68\xFF\xFF\xFF\x00\xC6\x85\x38\xFF\xFF\xFF\x4F\xC6\x85\x39\xFF\xFF"
    "\xFF\x75\xC6\x85\x3A\xFF\xFF\xFF\x74\xC6\x85\x3B\xFF\xFF\xFF\x70\xC6\x85"
    "\x3C\xFF\xFF\xFF\x75\xC6\x85\x3D\xFF\xFF\xFF\x74\xC6\x85\x3E\xFF\xFF\xFF"
    "\x44\xC6\x85\x3F\xFF\xFF\xFF\x65\xC6\x85\x40\xFF\xFF\xFF\x62\xC6\x85\x41"
    "\xFF\xFF\xFF\x75\xC6\x85\x42\xFF\xFF\xFF\x67\xC6\x85\x43\xFF\xFF\xFF\x53"
    "\xC6\x85\x44\xFF\xFF\xFF\x74\xC6\x85\x45\xFF\xFF\xFF\x72\xC6\x85\x46\xFF"
    "\xFF\xFF\x69\xC6\x85\x47\xFF\xFF\xFF\x6E\xC6\x85\x48\xFF\xFF\xFF\x67\xC6"
    "\x85\x49\xFF\xFF\xFF\x41\xC6\x85\x4A\xFF\xFF\xFF\x00\xC7\x45\x88\x43\x6C"
    "\x6F\x73\xC7\x45\x8C\x65\x48\x61\x6E\xC7\x45\x90\x64\x6C\x65\x00\xC6\x85"
    "\x24\xFF\xFF\xFF\x53\xC6\x85\x25\xFF\xFF\xFF\x65\xC6\x85\x26\xFF\xFF\xFF"
    "\x74\xC6\x85\x27\xFF\xFF\xFF\x54\xC6\x85\x28\xFF\xFF\xFF\x68\xC6\x85\x29"
    "\xFF\xFF\xFF\x72\x89\x85\xB4\xFE\xFF\xFF\x8D\x85\x4C\xFF\xFF\xFF\xC6\x85"
    "\x2A\xFF\xFF\xFF\x65\xC6\x85\x2B\xFF\xFF\xFF\x61\x89\x85\xB8\xFE\xFF\xFF"
    "\x8D\x45\xA0\xC6\x85\x2C\xFF\xFF\xFF\x64\xC6\x85\x2D\xFF\xFF\xFF\x45\x89"
    "\x85\xBC\xFE\xFF\xFF\x8D\x45\x94\xC6\x85\x2E\xFF\xFF\xFF\x72\xC6\x85\x2F"
    "\xFF\xFF\xFF\x72\x89\x85\xC0\xFE\xFF\xFF\x8D\x85\x5C\xFF\xFF\xFF\xC6\x85"
    "\x30\xFF\xFF\xFF\x6F\xC6\x85\x31\xFF\xFF\xFF\x72\x89\x85\xC4\xFE\xFF\xFF"
    "\x8D\x85\x38\xFF\xFF\xFF\xC6\x85\x32\xFF\xFF\xFF\x4D\xC6\x85\x33\xFF\xFF"
    "\xFF\x6F\x89\x85\xC8\xFE\xFF\xFF\x8D\x45\x88\xC6\x85\x34\xFF\xFF\xFF\x64"
    "\xC6\x85\x35\xFF\xFF\xFF\x65\x89\x85\xCC\xFE\xFF\xFF\x8D\x85\x24\xFF\xFF"
    "\xFF\xC6\x85\x36\xFF\xFF\xFF\x00\x89\x85\xD0\xFE\xFF\xFF\x32\xC9\x8D\x85"
    "\xFC\xFE\xFF\xFF\xC7\x85\xFC\xFE\xFF\xFF\x00\x00\x00\x00\x89\x85\x94\xFE"
    "\xFF\xFF\x8D\x85\xF8\xFE\xFF\xFF\x89\x85\x98\xFE\xFF\xFF\x8D\x85\xF4\xFE"
    "\xFF\xFF\x89\x85\x9C\xFE\xFF\xFF\x8D\x85\x0C\xFF\xFF\xFF\x89\x85\xA0\xFE"
    "\xFF\xFF\x8D\x85\x18\xFF\xFF\xFF\x89\x85\xA4\xFE\xFF\xFF\x8D\x45\xEC\x89"
    "\x85\xA8\xFE\xFF\xFF\x8D\x85\x14\xFF\xFF\xFF\x89\x85\xAC\xFE\xFF\xFF\x8D"
    "\x85\x10\xFF\xFF\xFF\x89\x85\xB0\xFE\xFF\xFF\x8D\x85\x7C\xFF\xFF\xFF\x89"
    "\x85\xD4\xFE\xFF\xFF\x8D\x85\xB4\xFE\xFF\xFF\x89\x85\xDC\xFE\xFF\xFF\x8D"
    "\x85\x94\xFE\xFF\xFF\x89\x85\xE0\xFE\xFF\xFF\x64\xA1\x30\x00\x00\x00\xC7"
    "\x85\xF8\xFE\xFF\xFF\x00\x00\x00\x00\xC7\x85\xF4\xFE\xFF\xFF\x00\x00\x00"
    "\x00\xC7\x85\x0C\xFF\xFF\xFF\x00\x00\x00\x00\xC7\x85\x18\xFF\xFF\xFF\x00"
    "\x00\x00\x00\xC7\x45\xEC\x00\x00\x00\x00\xC7\x85\x14\xFF\xFF\xFF\x00\x00"
    "\x00\x00\xC7\x85\x10\xFF\xFF\xFF\x00\x00\x00\x00\x8B\x40\x0C\x83\xC0\x14"
    "\xC7\x85\xD8\xFE\xFF\xFF\x0C\x00\x00\x00\xC7\x85\xE4\xFE\xFF\xFF\x08\x00"
    "\x00\x00\x89\x85\x08\xFF\xFF\xFF\x8B\x10\x3B\xD0\x0F\x84\xA9\x00\x00\x00"
    "\x8D\x64\x24\x00\x8B\xC2\x8D\x9D\xD4\xFE\xFF\xFF\x8B\x12\x89\x45\xE8\x89"
    "\x95\xE8\xFE\xFF\xFF\x8B\x50\x28\x66\x8B\x40\x24\x66\xD1\xE8\x89\x55\xFC"
    "\x0F\xB7\xF8\x89\x9D\x20\xFF\xFF\xFF\x8D\xA4\x24\x00\x00\x00\x00\x83\x7B"
    "\x10\x00\x74\x48\x3B\x7B\x04\x75\x43\x33\xC0\x33\xF6\x66\x3B\xC7\x73\x35"
    "\x8B\x1B\x0F\xB7\xCE\x0F\xB7\x14\x4A\x8D\x42\x9F\x66\x83\xF8\x19\x77\x06"
    "\x81\xC2\xE0\xFF\x00\x00\x0F\xBE\x0C\x0B\x0F\xB7\xC2\x3B\xC1\x75\x09\x8B"
    "\x55\xFC\x46\x66\x3B\xF7\x72\xD6\x8B\x9D\x20\xFF\xFF\xFF\x8B\x55\xFC\x66"
    "\x3B\xF7\x74\x71\x83\xC3\x14\x8D\x85\xE8\xFE\xFF\xFF\x89\x9D\x20\xFF\xFF"
    "\xFF\x3B\xD8\x75\x9F\x32\xC9\x8B\x95\xE8\xFE\xFF\xFF\x3B\x95\x08\xFF\xFF"
    "\xFF\x0F\x85\x5B\xFF\xFF\xFF\x8B\x55\x08\x8B\x32\x84\xC9\x0F\x85\x75\x01"
    "\x00\x00\x8B\x45\xEC\x85\xC0\x0F\x84\xA3\x03\x00\x00\x83\xFE\x01\x0F\x8C"
    "\x9A\x03\x00\x00\x8D\x4D\xF0\xC7\x45\xF0\x5B\x57\x48\x5D\x51\xC7\x45\xF4"
    "\x20\x45\x58\x50\x66\xC7\x45\xF8\x0A\x00\xFF\xD0\x8B\x85\x0C\xFF\xFF\xFF"
    "\x5F\x5E\x5B\x8B\xE5\x5D\xC2\x04\x00\x32\xC9\x85\xDB\x74\x9E\x8B\x45\xE8"
    "\x8B\x78\x10\x89\x7D\xD0\x8B\x47\x3C\x8B\x54\x38\x78\x8B\x44\x3A\x20\x03"
    "\xD7\x03\xC7\x89\x95\xEC\xFE\xFF\xFF\x89\x85\x00\xFF\xFF\xFF\x8B\x4A\x24"
    "\x8B\x72\x18\x03\xCF\x89\x8D\x1C\xFF\xFF\xFF\x8B\x4B\x10\x89\x75\xE8\x89"
    "\x4D\xFC\x85\xC9\x74\x6D\x85\xF6\x74\x69\x8B\x30\x8B\xD1\x03\xF7\x33\xFF"
    "\x85\xC9\x74\x34\x8B\x43\x08\x8A\x2E\x8D\xA4\x24\x00\x00\x00\x00\x8B\x14"
    "\xB8\x8A\x0A\x3A\xCD\x75\x17\x8B\xC6\x2B\xD6\x8D\x49\x00\x84\xC9\x74\x68"
    "\x8A\x4C\x02\x01\x40\x3A\x08\x74\xF3\x8B\x43\x08\x8B\x53\x10\x47\x3B\xFA"
    "\x72\xD8\x8B\x7D\xD0\x8B\x85\x00\xFF\xFF\xFF\x8B\xCA\x8B\x75\xE8\x83\xC0"
    "\x04\x83\x85\x1C\xFF\xFF\xFF\x02\x4E\x89\x85\x00\xFF\xFF\xFF\x89\x75\xE8"
    "\x89\x55\xFC\x85\xD2\x75\x93\xB1\x01\x8D\x85\xD4\xFE\xFF\xFF\x8D\xA4\x24"
    "\x00\x00\x00\x00\x83\x78\x10\x00\x0F\x87\xD7\xFE\xFF\xFF\x83\xC0\x14\x8D"
    "\x95\xE8\xFE\xFF\xFF\x3B\xC2\x75\xE9\xE9\xD9\xFE\xFF\xFF\x8B\x4B\x0C\x8B"
    "\x43\x10\x8B\x55\xFC\x48\x8B\x34\xB9\x3B\xF8\x73\x1A\x8B\x43\x08\x8B\x5B"
    "\x08\x8B\x44\x90\xFC\x89\x04\xBB\x8B\x44\x91\xFC\x8B\x9D\x20\xFF\xFF\xFF"
    "\x89\x04\xB9\x8B\x7D\xD0\x4A\x89\x53\x10\x85\xF6\x0F\x84\x75\xFF\xFF\xFF"
    "\x8B\x85\x1C\xFF\xFF\xFF\x0F\xB7\x08\x8B\x85\xEC\xFE\xFF\xFF\x8B\x40\x1C"
    "\x8D\x04\x88\x8B\x04\x38\x03\xC7\x89\x06\xE9\x54\xFF\xFF\xFF\x8D\x85\xF0"
    "\xFE\xFF\xFF\xC7\x45\xAC\x49\x6E\x6A\x65\x50\x6A\x01\xC7\x45\xB0\x63\x74"
    "\x49\x6E\x33\xFF\x66\xC7\x45\xB4\x69\x74\x33\xDB\xC6\x45\xB6\x00\xC7\x45"
    "\xFC\x00\x00\x00\x00\xFF\x95\x10\xFF\xFF\xFF\x83\xFE\x02\x7C\x18\x8D\x45"
    "\xC4\xC7\x45\xC4\x5B\x57\x48\x5D\x50\xC7\x45\xC8\x20\x4C\x4C\x0A\x88\x5D"
    "\xCC\xFF\x55\xEC\x8B\x45\x08\x83\xC0\x20\x50\xFF\x95\xFC\xFE\xFF\xFF\x89"
    "\x45\xE8\x85\xC0\x0F\x84\xC4\x00\x00\x00\x83\xFE\x02\x7C\x1E\x8D\x45\xB8"
    "\xC7\x45\xB8\x5B\x57\x48\x5D\x50\xC7\x45\xBC\x20\x47\x50\x41\x66\xC7\x45"
    "\xC0\x0A\x00\xFF\x55\xEC\x8B\x45\xE8\x8D\x4D\xAC\x51\x50\xFF\x95\xF8\xFE"
    "\xFF\xFF\x89\x85\x08\xFF\xFF\xFF\x85\xC0\x74\x71\x83\xFE\x02\x7C\x58\x8D"
    "\x45\xF0\xC7\x45\xF0\x5B\x57\x48\x5D\x50\xC7\x45\xF4\x20\x49\x49\x0A\x88"
    "\x5D\xF8\xFF\x55\xEC\xFF\x75\x08\xC7\x45\xFC\x01\x00\x00\x00\xFF\x95\x08"
    "\xFF\xFF\xFF\x8B\xF8\xC7\x45\xDC\x5B\x57\x48\x5D\x83\xC4\x04\xC7\x45\xE0"
    "\x20\x49\x49\x3A\x85\xFF\xC6\x45\xE4\x20\x66\xC7\x45\xE6\x0A\x00\x0F\x95"
    "\xC0\x04\x30\x88\x45\xE5\x8D\x45\xDC\x50\xFF\x55\xEC\xEB\x1C\x8B\x55\x08"
    "\x52\xC7\x45\xFC\x01\x00\x00\x00\xFF\xD0\x83\xC4\x04\x8B\xF8\xEB\x08\xFF"
    "\x95\x18\xFF\xFF\xFF\x8B\xD8\xFF\x75\xE8\xFF\x95\xF4\xFE\xFF\xFF\x85\xFF"
    "\x0F\x85\x02\x01\x00\x00\xEB\x08\xFF\x95\x18\xFF\xFF\xFF\x8B\xD8\x8B\x7D"
    "\x08\x8B\x47\x18\x85\xC0\x74\x07\x50\xFF\x95\x14\xFF\xFF\xFF\xFF\x77\x10"
    "\xFF\x95\x14\xFF\xFF\xFF\x83\x7D\xFC\x00\x0F\x85\xD4\x00\x00\x00\x83\xFE"
    "\x01\x0F\x8C\xCB\x00\x00\x00\x8B\xCB\xC7\x45\xD4\x5B\x57\x48\x5D\x83\xE1"
    "\x0F\xC7\x45\xD8\x20\x45\x52\x52\x83\xF9\x0A\x66\xC7\x45\xDC\x3A\x20\x66"
    "\xC7\x45\xE6\x0A\x00\x1A\xC0\x80\xC1\x37\x24\xF9\xC1\xEB\x04\x02\xC1\x8B"
    "\xCB\x88\x45\xE5\x83\xE1\x0F\x83\xF9\x0A\x1A\xC0\xC1\xEB\x04\x24\xF9\x04"
    "\x37\x02\xC1\x8B\xCB\x88\x45\xE4\x83\xE1\x0F\x83\xF9\x0A\x1A\xC0\xC1\xEB"
    "\x04\x24\xF9\x04\x37\x02\xC1\x8B\xCB\x88\x45\xE3\x83\xE1\x0F\x83\xF9\x0A"
    "\x1A\xC0\xC1\xEB\x04\x24\xF9\x04\x37\x02\xC1\x8B\xCB\x88\x45\xE2\x83\xE1"
    "\x0F\x83\xF9\x0A\x1A\xC0\xC1\xEB\x04\x24\xF9\x04\x37\x02\xC1\x8B\xCB\x88"
    "\x45\xE1\x83\xE1\x0F\x83\xF9\x0A\x1A\xC0\xC1\xEB\x04\x24\xF9\x04\x37\x02"
    "\xC1\x8B\xCB\x88\x45\xE0\x83\xE1\x0F\x83\xF9\x0A\x1A\xC0\x80\xC1\x37\x24"
    "\xF9\xC1\xEB\x04\x02\xC1\x83\xFB\x0A\x88\x45\xDF\x1A\xC0\x24\xF9\x04\x37"
    "\x02\xC3\x88\x45\xDE\x8D\x45\xD4\x50\xFF\x55\xEC\x6A\x00\xFF\xB5\xF0\xFE"
    "\xFF\xFF\xFF\x95\x10\xFF\xFF\xFF\x8B\x85\x0C\xFF\xFF\xFF\x5F\x5E\x5B\x8B"
    "\xE5\x5D\xC2\x04\x00";

constexpr SIZE_T x32APCShellcodeSize = sizeof(x32APCShellcode) - 1;

const BYTE* x32Shellcode =
    x32APCShellcode + sizeof(PRE_X32SHELLCODE_ARGS_3_TO_1) - 1;
constexpr SIZE_T x32ShellcodeSize =
    (sizeof(x32APCShellcode) - 1) - (sizeof(PRE_X32SHELLCODE_ARGS_3_TO_1) - 1);

#define PRE_X64SHELLCODE_VIRTUAL_FREE                             \
    "\x48\x83\xEC\x28"             /* sub rsp,28               */ \
    "\xE8\x20\x00\x00\x00"         /* call $+20                */ \
    "\x48\x83\xC4\x28"             /* add rsp,28               */ \
    "\x48\x85\xC0"                 /* test rax,rax             */ \
    "\x75\x01"                     /* jne $+1                  */ \
    "\xC3"                         /* ret                      */ \
    "\x48\x8D\x0D\x00\x00\x00\x00" /* lea rcx,qword ptr ds:[$] */ \
    "\x66\x81\xE1\x00\xF0"         /* and cx,F000              */ \
    "\x33\xD2"                     /* xor edx,edx              */ \
    "\x41\xB8\x00\x80\x00\x00"     /* mov r8d,8000             */ \
    "\xFF\xE0"                     /* jmp rax                  */

// The 64-bit InjectShellcode function from the project in the inject_shellcode
// subfolder.
const BYTE x64Shellcode[] = PRE_X64SHELLCODE_VIRTUAL_FREE
    "\x48\x89\x4C\x24\x08\x55\x53\x56\x57\x41\x54\x41\x55\x41\x56\x41\x57\x48"
    "\x8D\xAC\x24\xE8\xFE\xFF\xFF\x48\x81\xEC\x18\x02\x00\x00\xC7\x45\xA8\x4B"
    "\x45\x52\x4E\x48\x8D\x45\xB8\xC7\x45\xAC\x45\x4C\x33\x32\x4C\x8B\xE9\xC7"
    "\x45\xB0\x2E\x44\x4C\x4C\x33\xD2\xC7\x45\xB8\x4C\x6F\x61\x64\xC7\x45\xBC"
    "\x4C\x69\x62\x72\xC7\x45\xC0\x61\x72\x79\x57\xC6\x45\xC4\x00\xC7\x45\xD8"
    "\x47\x65\x74\x50\xC7\x45\xDC\x72\x6F\x63\x41\xC7\x45\xE0\x64\x64\x72\x65"
    "\x66\xC7\x45\xE4\x73\x73\xC6\x45\xE6\x00\xC7\x44\x24\x78\x46\x72\x65\x65"
    "\xC7\x44\x24\x7C\x4C\x69\x62\x72\xC7\x45\x80\x61\x72\x79\x00\xC7\x45\x88"
    "\x56\x69\x72\x74\xC7\x45\x8C\x75\x61\x6C\x46\xC7\x45\x90\x72\x65\x65\x00"
    "\xC7\x45\xC8\x47\x65\x74\x4C\xC7\x45\xCC\x61\x73\x74\x45\xC7\x45\xD0\x72"
    "\x72\x6F\x72\xC6\x45\xD4\x00\xC6\x45\xE8\x4F\xC6\x45\xE9\x75\xC6\x45\xEA"
    "\x74\xC6\x45\xEB\x70\xC6\x45\xEC\x75\xC6\x45\xED\x74\xC6\x45\xEE\x44\xC6"
    "\x45\xEF\x65\xC6\x45\xF0\x62\xC6\x45\xF1\x75\xC6\x45\xF2\x67\xC6\x45\xF3"
    "\x53\xC6\x45\xF4\x74\xC6\x45\xF5\x72\xC6\x45\xF6\x69\xC6\x45\xF7\x6E\xC6"
    "\x45\xF8\x67\xC6\x45\xF9\x41\xC6\x45\xFA\x00\xC7\x45\x98\x43\x6C\x6F\x73"
    "\xC7\x45\x9C\x65\x48\x61\x6E\xC7\x45\xA0\x64\x6C\x65\x00\xC6\x45\x00\x53"
    "\xC6\x45\x01\x65\xC6\x45\x02\x74\xC6\x45\x03\x54\xC6\x45\x04\x68\xC6\x45"
    "\x05\x72\xC6\x45\x06\x65\xC6\x45\x07\x61\xC6\x45\x08\x64\xC6\x45\x09\x45"
    "\xC6\x45\x0A\x72\x48\x89\x85\x90\x00\x00\x00\x48\x8D\x45\xD8\xC6\x45\x0B"
    "\x72\x48\x89\x85\x98\x00\x00\x00\x48\x8D\x44\x24\x78\xC6\x45\x0C\x6F\x48"
    "\x89\x85\xA0\x00\x00\x00\x48\x8D\x45\x88\xC6\x45\x0D\x72\x48\x89\x85\xA8"
    "\x00\x00\x00\x48\x8D\x45\xC8\xC6\x45\x0E\x4D\x48\x89\x85\xB0\x00\x00\x00"
    "\x48\x8D\x45\xE8\xC6\x45\x0F\x6F\x48\x89\x85\xB8\x00\x00\x00\x48\x8D\x45"
    "\x98\xC6\x45\x10\x64\x48\x89\x85\xC0\x00\x00\x00\x48\x8D\x45\x00\xC6\x45"
    "\x11\x65\xC6\x45\x12\x00\x48\x89\x85\xC8\x00\x00\x00\x48\x8D\x45\x30\x48"
    "\x89\x55\x30\x48\x89\x85\xD0\x00\x00\x00\x32\xC9\x48\x89\x55\x38\x48\x8D"
    "\x45\x38\x48\x89\x85\xD8\x00\x00\x00\x48\x8D\x45\x40\x48\x89\x85\xE0\x00"
    "\x00\x00\x48\x8D\x45\x28\x48\x89\x85\xE8\x00\x00\x00\x48\x8D\x85\x78\x01"
    "\x00\x00\x48\x89\x85\xF0\x00\x00\x00\x48\x8D\x85\x70\x01\x00\x00\x48\x89"
    "\x85\xF8\x00\x00\x00\x48\x8D\x45\x18\x48\x89\x85\x00\x01\x00\x00\x48\x8D"
    "\x45\x20\x48\x89\x85\x08\x01\x00\x00\x48\x8D\x45\xA8\x48\x89\x45\x60\x48"
    "\x8D\x85\x90\x00\x00\x00\x48\x89\x45\x70\x48\x8D\x85\xD0\x00\x00\x00\x48"
    "\x89\x55\x40\x48\x89\x55\x28\x48\x89\x95\x78\x01\x00\x00\x48\x89\x95\x70"
    "\x01\x00\x00\x48\x89\x55\x18\x48\x89\x55\x20\x48\x89\x45\x78\x65\x48\x8B"
    "\x04\x25\x60\x00\x00\x00\x48\xC7\x45\x68\x0C\x00\x00\x00\x48\xC7\x85\x80"
    "\x00\x00\x00\x08\x00\x00\x00\x4C\x8B\x40\x18\x49\x8B\x40\x20\x49\x83\xC0"
    "\x20\x4C\x89\x45\x58\x49\x3B\xC0\x0F\x84\xA6\x00\x00\x00\x66\x66\x0F\x1F"
    "\x84\x00\x00\x00\x00\x00\x44\x0F\xB7\x58\x48\x48\x8D\x30\x48\x8B\x00\x4C"
    "\x8D\x55\x60\x48\x8B\x7E\x50\x66\x41\xD1\xEB\x48\x89\x45\x50\x0F\x1F\x44"
    "\x00\x00\x49\x83\x7A\x20\x00\x74\x4E\x41\x0F\xB7\xC3\x49\x3B\x42\x08\x75"
    "\x44\x44\x0F\xB7\xCA\x66\x41\x3B\xD3\x73\x34\x49\x8B\x1A\x66\x90\x45\x0F"
    "\xB7\xC1\x42\x0F\xB7\x14\x47\x8D\x42\x9F\x66\x83\xF8\x19\x8D\x4A\xE0\x42"
    "\x0F\xBE\x04\x03\x66\x0F\x47\xCA\x0F\xB7\xC9\x3B\xC8\x75\x0A\x66\x41\xFF"
    "\xC1\x66\x45\x3B\xCB\x72\xD3\x33\xD2\x66\x45\x3B\xCB\x74\x6F\x49\x83\xC2"
    "\x28\x48\x8D\x85\x88\x00\x00\x00\x4C\x3B\xD0\x75\x9B\x32\xC9\x48\x8B\x45"
    "\x50\x48\x3B\x45\x58\x0F\x85\x6B\xFF\xFF\xFF\x4C\x8B\xAD\x60\x01\x00\x00"
    "\x41\x8B\x5D\x00\x84\xC9\x0F\x85\x68\x01\x00\x00\x48\x8B\x85\x70\x01\x00"
    "\x00\x48\x85\xC0\x0F\x84\xAC\x03\x00\x00\x83\xFB\x01\x0F\x8C\xA3\x03\x00"
    "\x00\x48\x8D\x4C\x24\x20\xC7\x44\x24\x20\x5B\x57\x48\x5D\xC7\x44\x24\x24"
    "\x20\x45\x58\x50\x66\xC7\x44\x24\x28\x0A\x00\xFF\xD0\xE9\x80\x03\x00\x00"
    "\x32\xC9\x4D\x85\xD2\x74\x9C\x4C\x8B\x76\x20\x49\x8B\x7A\x20\x49\x63\x46"
    "\x3C\x42\x8B\x84\x30\x88\x00\x00\x00\x49\x03\xC6\x48\x89\x45\x48\x44\x8B"
    "\x78\x20\x44\x8B\x60\x24\x4D\x03\xFE\x44\x8B\x68\x18\x4D\x03\xE6\x48\x85"
    "\xFF\x0F\x84\xC3\x00\x00\x00\x45\x85\xED\x0F\x84\xBA\x00\x00\x00\x45\x8B"
    "\x1F\x4C\x8B\xCA\x4D\x03\xDE\x4C\x8B\xC7\x48\x85\xFF\x0F\x84\x8E\x00\x00"
    "\x00\x49\x8B\x5A\x10\x41\x0F\xB6\x33\x66\x0F\x1F\x84\x00\x00\x00\x00\x00"
    "\x4A\x8B\x14\xCB\x0F\xB6\x0A\x40\x3A\xCE\x75\x16\x49\x8B\xC3\x49\x2B\xD3"
    "\x84\xC9\x74\x1A\x0F\xB6\x4C\x02\x01\x48\xFF\xC0\x3A\x08\x74\xF0\x4D\x8B"
    "\x42\x20\x49\xFF\xC1\x4D\x3B\xC8\x72\xD2\xEB\x4B\x49\x8B\x4A\x18\x49\x8B"
    "\x42\x20\x48\xFF\xC8\x4E\x8B\x1C\xC9\x4C\x3B\xC8\x73\x12\x48\x8B\x44\xFB"
    "\xF8\x4A\x89\x04\xCB\x48\x8B\x44\xF9\xF8\x4A\x89\x04\xC9\x4C\x8D\x47\xFF"
    "\x4D\x89\x42\x20\x4D\x85\xDB\x74\x18\x48\x8B\x45\x48\x41\x0F\xB7\x14\x24"
    "\x8B\x48\x1C\x49\x03\xCE\x8B\x04\x91\x49\x03\xC6\x49\x89\x03\x33\xD2\x49"
    "\x83\xC7\x04\x49\x83\xC4\x02\x41\xFF\xCD\x49\x8B\xF8\x4D\x85\xC0\x0F\x85"
    "\x3D\xFF\xFF\xFF\xB1\x01\x48\x8D\x45\x60\x66\x0F\x1F\x44\x00\x00\x48\x83"
    "\x78\x20\x00\x0F\x87\x8A\xFE\xFF\xFF\x48\x83\xC0\x28\x4C\x8D\x85\x88\x00"
    "\x00\x00\x49\x3B\xC0\x75\xE5\xE9\x85\xFE\xFF\xFF\x8B\xF2\xC7\x44\x24\x68"
    "\x49\x6E\x6A\x65\x8B\xFA\xC7\x44\x24\x6C\x63\x74\x49\x6E\x48\x8D\x95\x68"
    "\x01\x00\x00\x66\xC7\x44\x24\x70\x69\x74\xB9\x01\x00\x00\x00\xC6\x44\x24"
    "\x72\x00\xFF\x55\x20\x83\xFB\x02\x7C\x20\x48\x8D\x4C\x24\x48\xC7\x44\x24"
    "\x48\x5B\x57\x48\x5D\xC7\x44\x24\x4C\x20\x4C\x4C\x0A\xC6\x44\x24\x50\x00"
    "\xFF\x95\x70\x01\x00\x00\x49\x8D\x4D\x20\xFF\x55\x30\x4C\x8B\xF0\x48\x85"
    "\xC0\x0F\x84\xCC\x00\x00\x00\x83\xFB\x02\x7C\x22\x48\x8D\x4C\x24\x58\xC7"
    "\x44\x24\x58\x5B\x57\x48\x5D\xC7\x44\x24\x5C\x20\x47\x50\x41\x66\xC7\x44"
    "\x24\x60\x0A\x00\xFF\x95\x70\x01\x00\x00\x48\x8D\x54\x24\x68\x49\x8B\xCE"
    "\xFF\x55\x38\x4C\x8B\xF8\x48\x85\xC0\x74\x77\x83\xFB\x02\x7C\x62\x48\x8D"
    "\x4C\x24\x20\xC7\x44\x24\x20\x5B\x57\x48\x5D\xC7\x44\x24\x24\x20\x49\x49"
    "\x0A\xC6\x44\x24\x28\x00\xFF\x95\x70\x01\x00\x00\x49\x8B\xCD\x41\xBC\x01"
    "\x00\x00\x00\x41\xFF\xD7\x85\xC0\xC7\x44\x24\x30\x5B\x57\x48\x5D\x8B\xF0"
    "\xC7\x44\x24\x34\x20\x49\x49\x3A\x0F\x95\xC0\xC6\x44\x24\x38\x20\x04\x30"
    "\x66\xC7\x44\x24\x3A\x0A\x00\x48\x8D\x4C\x24\x30\x88\x44\x24\x39\xFF\x95"
    "\x70\x01\x00\x00\xEB\x1B\x49\x8B\xCD\x41\xBC\x01\x00\x00\x00\x41\xFF\xD7"
    "\x8B\xF0\xEB\x0B\xFF\x95\x78\x01\x00\x00\x8B\xF8\x45\x33\xE4\x49\x8B\xCE"
    "\xFF\x55\x40\x85\xF6\x0F\x85\x18\x01\x00\x00\xEB\x0B\xFF\x95\x78\x01\x00"
    "\x00\x8B\xF8\x45\x33\xE4\x49\x8B\x4D\x18\x48\x85\xC9\x74\x03\xFF\x55\x18"
    "\x49\x8B\x4D\x10\xFF\x55\x18\x45\x85\xE4\x0F\x85\xEF\x00\x00\x00\x83\xFB"
    "\x01\x0F\x8C\xE6\x00\x00\x00\x8B\xCF\xC7\x44\x24\x30\x5B\x57\x48\x5D\x83"
    "\xE1\x0F\xC7\x44\x24\x34\x20\x45\x52\x52\x83\xF9\x0A\x66\xC7\x44\x24\x38"
    "\x3A\x20\xBA\x30\x00\x00\x00\x66\xC7\x44\x24\x42\x0A\x00\x41\xB8\x37\x00"
    "\x00\x00\x8B\xC2\x41\x0F\x43\xC0\xC1\xEF\x04\x02\xC1\x8B\xCF\x83\xE1\x0F"
    "\x88\x44\x24\x41\x83\xF9\x0A\x8B\xC2\x41\x0F\x43\xC0\xC1\xEF\x04\x02\xC1"
    "\x8B\xCF\x83\xE1\x0F\x88\x44\x24\x40\x83\xF9\x0A\x8B\xC2\x41\x0F\x43\xC0"
    "\xC1\xEF\x04\x02\xC1\x8B\xCF\x83\xE1\x0F\x88\x44\x24\x3F\x83\xF9\x0A\x8B"
    "\xC2\x41\x0F\x43\xC0\xC1\xEF\x04\x02\xC1\x8B\xCF\x83\xE1\x0F\x88\x44\x24"
    "\x3E\x83\xF9\x0A\x8B\xC2\x41\x0F\x43\xC0\xC1\xEF\x04\x02\xC1\x8B\xCF\x83"
    "\xE1\x0F\x88\x44\x24\x3D\x83\xF9\x0A\x8B\xC2\x41\x0F\x43\xC0\xC1\xEF\x04"
    "\x02\xC1\x8B\xCF\x83\xE1\x0F\x88\x44\x24\x3C\x83\xF9\x0A\x8B\xC2\x41\x0F"
    "\x43\xC0\xC1\xEF\x04\x02\xC1\x83\xE7\x0F\x83\xFF\x0A\x88\x44\x24\x3B\x48"
    "\x8D\x4C\x24\x30\x41\x0F\x43\xD0\x40\x02\xD7\x88\x54\x24\x3A\xFF\x95\x70"
    "\x01\x00\x00\x8B\x8D\x68\x01\x00\x00\x33\xD2\xFF\x55\x20\x48\x8B\x45\x28"
    "\x48\x81\xC4\x18\x02\x00\x00\x41\x5F\x41\x5E\x41\x5D\x41\x5C\x5F\x5E\x5B"
    "\x5D\xC3";

constexpr SIZE_T x64ShellcodeSize = sizeof(x64Shellcode) - 1;

//
// Reference: https://repnz.github.io/posts/apc/wow64-user-apc/
//
ULONG64 EncodeWow64ApcRoutine(ULONG64 ApcRoutine) {
    return (ULONG64)((-(INT64)ApcRoutine) << 2);
}

//
// Reference: https://repnz.github.io/posts/apc/user-apc/
//
BOOL MyQueueUserAPC(PAPCFUNC pfnAPC,
                    HANDLE hThread,
                    ULONG_PTR dwData,
                    USHORT targetProcessArch) {
#ifndef _WIN64
    if (targetProcessArch == IMAGE_FILE_MACHINE_AMD64) {
        // WOW64 to x64 native, use heaven's gate.
        //
        // "Microsoft added a validation to prevent a programming error:
        // If you try to queue an APC from a 32 bit process to a 64 bit
        // process and you use a 32 bit address, you'll get this status code:
        // [...] STATUS_INVALID_HANDLE"
        // https://repnz.github.io/posts/apc/wow64-user-apc/
        return NtQueueApcThread64(HANDLE_TO_DWORD64(hThread),
                                  PTR_TO_DWORD64(pfnAPC), (DWORD64)dwData, 0,
                                  0);
    }
#endif  // _WIN64

    using NtQueueApcThread_t = DWORD(WINAPI*)(
        IN HANDLE ThreadHandle, IN PVOID ApcDispatchRoutine,
        IN ULONG_PTR SystemArgument1, IN ULONG_PTR SystemArgument2,
        IN ULONG_PTR SystemArgument3);

    GET_PROC_ADDRESS_ONCE(NtQueueApcThread_t, pNtQueueApcThread, L"ntdll.dll",
                          "NtQueueApcThread");

    if (!pNtQueueApcThread) {
        SetLastError(ERROR_PROC_NOT_FOUND);
        return FALSE;
    }

#ifdef _WIN64
    if (targetProcessArch == IMAGE_FILE_MACHINE_I386) {
        // x64 native to WOW64, encode address.
        pfnAPC = (PAPCFUNC)EncodeWow64ApcRoutine((ULONG64)pfnAPC);
    }
#endif  // _WIN64

    NTSTATUS result = pNtQueueApcThread(hThread, pfnAPC, dwData, 0, 0);
    if (result < 0) {
        SetLastError(LsaNtStatusToWinError(result));
        return FALSE;
    }

    return TRUE;
}

USHORT GetProcessArch(HANDLE hProcess) {
    // For now, only IMAGE_FILE_MACHINE_I386 and IMAGE_FILE_MACHINE_AMD64.
    // TODO: Use IsWow64Process2 if available.

#ifndef _WIN64
    SYSTEM_INFO siSystemInfo;
    GetNativeSystemInfo(&siSystemInfo);
    if (siSystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) {
        // 32-bit machine, only one option.
        return IMAGE_FILE_MACHINE_I386;
    }
#endif  // _WIN64

    BOOL bIsWow64Process;
    if (IsWow64Process(hProcess, &bIsWow64Process) && bIsWow64Process) {
        return IMAGE_FILE_MACHINE_I386;
    }

    return IMAGE_FILE_MACHINE_AMD64;
}

}  // namespace

namespace DllInject {

void DllInject(HANDLE hProcess,
               HANDLE hThreadForAPC,
               HANDLE hSessionManagerProcess,
               HANDLE hSessionMutex,
               bool threadAttachExempt) {
    const BYTE* shellcode;
    size_t shellcodeSize;

    USHORT targetProcessArch = GetProcessArch(hProcess);
    switch (targetProcessArch) {
        case IMAGE_FILE_MACHINE_I386:
            if (hThreadForAPC) {
                // The calling convention is different - three arguments instead
                // of one.
                shellcode = x32APCShellcode;
                shellcodeSize = x32APCShellcodeSize;
            } else {
                shellcode = x32Shellcode;
                shellcodeSize = x32ShellcodeSize;
            }
            break;

        case IMAGE_FILE_MACHINE_AMD64:
            shellcode = x64Shellcode;
            shellcodeSize = x64ShellcodeSize;
            break;

        default:
            throw std::logic_error("Invalid architecture value");
    }

    std::wstring dllPath =
        StorageManager::GetInstance().GetEnginePath(targetProcessArch) /
        L"windhawk.dll";
    size_t dllPathBytes = (dllPath.length() + 1) * sizeof(WCHAR);

    HANDLE hRemoteSessionManagerProcess;
    THROW_IF_WIN32_BOOL_FALSE(DuplicateHandle(
        GetCurrentProcess(), hSessionManagerProcess, hProcess,
        &hRemoteSessionManagerProcess,
        PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE, FALSE, 0));

    auto remoteSessionManagerProcessCleanup =
        wil::scope_exit([hProcess, hRemoteSessionManagerProcess] {
            DuplicateHandle(hProcess, hRemoteSessionManagerProcess, nullptr,
                            nullptr, 0, FALSE, DUPLICATE_CLOSE_SOURCE);
        });

    HANDLE hRemoteSessionMutex = nullptr;
    if (hSessionMutex) {
        THROW_IF_WIN32_BOOL_FALSE(DuplicateHandle(
            GetCurrentProcess(), hSessionMutex, hProcess, &hRemoteSessionMutex,
            PROCESS_QUERY_LIMITED_INFORMATION, FALSE, 0));
    }

    auto remoteSessionMutexCleanup =
        wil::scope_exit([hProcess, hRemoteSessionMutex] {
            if (hRemoteSessionMutex) {
                DuplicateHandle(hProcess, hRemoteSessionMutex, nullptr, nullptr,
                                0, FALSE, DUPLICATE_CLOSE_SOURCE);
            }
        });

    size_t shellcodeDataSize =
        offsetof(LOAD_LIBRARY_REMOTE_DATA, szDllName) + dllPathBytes;
    auto shellcodeDataVector = std::vector<BYTE>(shellcodeDataSize);
    auto shellcodeData =
        reinterpret_cast<LOAD_LIBRARY_REMOTE_DATA*>(shellcodeDataVector.data());

    shellcodeData->nLogVerbosity =
        static_cast<INT32>(Logger::GetInstance().GetVerbosity());
    shellcodeData->bRunningFromAPC = !!hThreadForAPC;
    shellcodeData->bThreadAttachExempt = threadAttachExempt;
    shellcodeData->hSessionManagerProcess = hRemoteSessionManagerProcess;
    shellcodeData->hSessionMutex = hRemoteSessionMutex;
    memcpy(shellcodeData->szDllName, dllPath.c_str(), dllPathBytes);

    size_t shellcodeSizeAligned =
        (shellcodeSize + (sizeof(LONG_PTR) - 1)) & ~(sizeof(LONG_PTR) - 1);

    // Allocate enough memory in the remote process's address space
    // to hold the shellcode and the data struct.
    void* pRemoteCode = VirtualAllocEx(
        hProcess, nullptr, shellcodeSizeAligned + shellcodeDataSize,
        MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    THROW_LAST_ERROR_IF_NULL(pRemoteCode);

    auto remoteCodeCleanup = wil::scope_exit([hProcess, pRemoteCode] {
        VirtualFreeEx(hProcess, pRemoteCode, 0, MEM_RELEASE);
    });

    // Write our shellcode into the remote process.
    THROW_IF_WIN32_BOOL_FALSE(WriteProcessMemory(
        hProcess, pRemoteCode, shellcode, shellcodeSize, nullptr));

    // Write a copy of our struct to the remote process.
    void* pRemoteData =
        reinterpret_cast<BYTE*>(pRemoteCode) + shellcodeSizeAligned;
    THROW_IF_WIN32_BOOL_FALSE(WriteProcessMemory(
        hProcess, pRemoteData, shellcodeData, shellcodeDataSize, nullptr));

    // Mark shellcode as executable.
    DWORD oldProtect;
    THROW_IF_WIN32_BOOL_FALSE(VirtualProtectEx(
        hProcess, pRemoteCode, shellcodeSize, PAGE_EXECUTE_READ, &oldProtect));

    if (hThreadForAPC) {
        THROW_IF_WIN32_BOOL_FALSE(MyQueueUserAPC(
            reinterpret_cast<PAPCFUNC>(pRemoteCode), hThreadForAPC,
            reinterpret_cast<ULONG_PTR>(pRemoteData), targetProcessArch));
    } else {
        DWORD createThreadFlags = 0;

        if (threadAttachExempt) {
            createThreadFlags |=
                Functions::MY_REMOTE_THREAD_THREAD_ATTACH_EXEMPT;
        }

        if (Functions::IsWindowsVersionOrGreaterWithBuildNumber(10, 0, 18362)) {
            createThreadFlags |=
                Functions::MY_REMOTE_THREAD_BYPASS_PROCESS_FREEZE;
        }

#ifndef _WIN64
        if (targetProcessArch == IMAGE_FILE_MACHINE_AMD64) {
            // WOW64 to x64 native, use heaven's gate.
            wil::unique_process_handle remoteThread(
                (HANDLE)CreateRemoteThread64(
                    HANDLE_TO_DWORD64(hProcess), PTR_TO_DWORD64(pRemoteCode),
                    PTR_TO_DWORD64(pRemoteData), createThreadFlags));
            THROW_LAST_ERROR_IF_NULL(remoteThread);
        } else
#endif  // _WIN64
        {
            wil::unique_process_handle remoteThread(
                Functions::MyCreateRemoteThread(
                    hProcess,
                    reinterpret_cast<LPTHREAD_START_ROUTINE>(pRemoteCode),
                    pRemoteData, createThreadFlags));
            THROW_LAST_ERROR_IF_NULL(remoteThread);
        }
    }

    remoteSessionManagerProcessCleanup.release();
    remoteSessionMutexCleanup.release();
    remoteCodeCleanup.release();
}

}  // namespace DllInject
